texture: Change download vfunc
authorBenjamin Otte <otte@redhat.com>
Mon, 12 Mar 2018 16:17:30 +0000 (17:17 +0100)
committerBenjamin Otte <otte@redhat.com>
Mon, 12 Mar 2018 16:21:45 +0000 (17:21 +0100)
A problem with textures is that they can become too big for GPU memory,
which would require tiling. But for tiling we only need to download
the pixels needed by the tile.

Similarly, there might be interest to not upload full textures if a
renderer knows it only needs a small part.

Both of these methods require the ability to specify an area of the
texture to be downloaded. So change the download vfunc to include
this parameter now before we add even more textures later.

A private gdk_texture_download_area() function has also been added, but
nobody is using it yet.

gdk/gdkgltexture.c
gdk/gdkmemorytexture.c
gdk/gdktexture.c
gdk/gdktextureprivate.h

index e2f51c12d671cb2cdf8cd4a16886dd8fae6c0bb0..6a0185626a1149a5f6b1dfe0413a51b41c231d2e 100644 (file)
@@ -68,9 +68,10 @@ gdk_gl_texture_dispose (GObject *object)
 }
 
 static void
-gdk_gl_texture_download (GdkTexture *texture,
-                         guchar     *data,
-                         gsize       stride)
+gdk_gl_texture_download (GdkTexture         *texture,
+                         const GdkRectangle *area,
+                         guchar             *data,
+                         gsize               stride)
 {
   GdkGLTexture *self = GDK_GL_TEXTURE (texture);
   cairo_surface_t *surface;
@@ -78,7 +79,7 @@ gdk_gl_texture_download (GdkTexture *texture,
 
   surface = cairo_image_surface_create_for_data (data,
                                                  CAIRO_FORMAT_ARGB32,
-                                                 texture->width, texture->height,
+                                                 area->width, area->height,
                                                  stride);
 
   cr = cairo_create (surface);
@@ -93,8 +94,9 @@ gdk_gl_texture_download (GdkTexture *texture,
       GdkWindow *window;
 
       window = gdk_gl_context_get_window (self->context);
-      gdk_cairo_draw_from_gl (cr, window, self->id, GL_TEXTURE, 1, 0, 0,
-                              texture->width, texture->height);
+      gdk_cairo_draw_from_gl (cr, window, self->id, GL_TEXTURE, 1, 
+                              area->x, area->y,
+                              area->width, area->height);
     }
 
   cairo_destroy (cr);
index f44dff2139823559a7727cf69fba78b3548dfe08..7a84e3962f1fcff19c6b71de9a706d9fcf1a73e2 100644 (file)
@@ -38,6 +38,30 @@ struct _GdkMemoryTextureClass
 
 G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
 
+static gsize
+gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
+{
+  switch (format)
+    {
+    case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+    case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+    case GDK_MEMORY_B8G8R8A8:
+    case GDK_MEMORY_A8R8G8B8:
+    case GDK_MEMORY_R8G8B8A8:
+    case GDK_MEMORY_A8B8G8R8:
+      return 4;
+
+    case GDK_MEMORY_R8G8B8:
+    case GDK_MEMORY_B8G8R8:
+      return 3;
+
+    case GDK_MEMORY_N_FORMATS:
+    default:
+      g_assert_not_reached ();
+      return 4;
+    }
+}
+
 static void
 gdk_memory_texture_dispose (GObject *object)
 {
@@ -49,17 +73,21 @@ gdk_memory_texture_dispose (GObject *object)
 }
 
 static void
-gdk_memory_texture_download (GdkTexture *texture,
-                             guchar     *data,
-                             gsize       stride)
+gdk_memory_texture_download (GdkTexture         *texture,
+                             const GdkRectangle *area,
+                             guchar             *data,
+                             gsize               stride)
 {
   GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
 
   gdk_memory_convert (data, stride,
                       GDK_MEMORY_CAIRO_FORMAT_ARGB32,
-                      g_bytes_get_data (self->bytes, NULL), self->stride,
+                      (guchar *) g_bytes_get_data (self->bytes, NULL)
+                        + area->x * gdk_memory_format_bytes_per_pixel (self->format)
+                        + area->y * self->stride,
+                      self->stride,
                       self->format,
-                      texture->width, texture->height);
+                      area->width, area->height);
 }
 
 static void
index 616b0cbb8bb7a07d82d5f487144437eea13d5dab..6e42f0a952ced8440a871ac902667638a827b004 100644 (file)
@@ -77,9 +77,10 @@ G_DEFINE_ABSTRACT_TYPE (GdkTexture, gdk_texture, G_TYPE_OBJECT)
   g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj))
 
 static void
-gdk_texture_real_download (GdkTexture *self,
-                           guchar     *data,
-                           gsize       stride)
+gdk_texture_real_download (GdkTexture         *self,
+                           const GdkRectangle *area,
+                           guchar             *data,
+                           gsize               stride)
 {
   GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download);
 }
@@ -431,7 +432,21 @@ gdk_texture_download_surface (GdkTexture *texture)
   return GDK_TEXTURE_GET_CLASS (texture)->download_surface (texture);
 }
 
-/**
+void
+gdk_texture_download_area (GdkTexture         *texture,
+                           const GdkRectangle *area,
+                           guchar             *data,
+                           gsize               stride)
+{
+  g_assert (area->x >= 0);
+  g_assert (area->y >= 0);
+  g_assert (area->x + area->width <= texture->width);
+  g_assert (area->y + area->height <= texture->height);
+
+  return GDK_TEXTURE_GET_CLASS (texture)->download (texture, area, data, stride);
+}
+
+/*
  * gdk_texture_download:
  * @texture: a #GdkTexture
  * @data: (array): pointer to enough memory to be filled with the
@@ -466,7 +481,10 @@ gdk_texture_download (GdkTexture *texture,
   g_return_if_fail (data != NULL);
   g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
 
-  return GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
+  gdk_texture_download_area (texture,
+                             &(GdkRectangle) { 0, 0, texture->width, texture->height },
+                             data,
+                             stride);
 }
 
 gboolean
index f9e5fbe908ee1efdb0f94fcd1f687dac146501b1..07cb5436a33f91af277dbcea532e60a792fe419e 100644 (file)
@@ -25,6 +25,7 @@ struct _GdkTextureClass {
   GObjectClass parent_class;
 
   void                  (* download)                    (GdkTexture             *texture,
+                                                         const GdkRectangle     *area,
                                                          guchar                 *data,
                                                          gsize                   stride);
   cairo_surface_t *     (* download_surface)            (GdkTexture             *texture);
@@ -35,6 +36,10 @@ gpointer                gdk_texture_new                 (const GdkTextureClass
                                                          int                     height);
 GdkTexture *            gdk_texture_new_for_surface     (cairo_surface_t        *surface);
 cairo_surface_t *       gdk_texture_download_surface    (GdkTexture             *texture);
+void                    gdk_texture_download_area       (GdkTexture             *texture,
+                                                         const GdkRectangle     *area,
+                                                         guchar                 *data,
+                                                         gsize                   stride);
 
 gboolean                gdk_texture_set_render_data     (GdkTexture             *self,
                                                          gpointer                key,